/*
 * Copyright (c) 2024 Huawei Technologies Co., Ltd.
 * openFuyao is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

package k8sconfig

import (
	"errors"
	"os"
	"os/user"
	"testing"

	"github.com/agiledragon/gomonkey/v2"
	"github.com/stretchr/testify/assert"
	"k8s.io/client-go/util/homedir"
)

const (
	qps   = 1000000
	burst = 1000000
)

func TestNewKubernetesConfig(t *testing.T) {
	t.Run("create new kubernetes config", func(t *testing.T) {
		config := NewKubernetesConfig()
		assert.NotNil(t, config)
		assert.Equal(t, float32(qps), config.QPS)
		assert.Equal(t, burst, config.Burst)
	})
}

func TestKubernetesConfigValidate(t *testing.T) {
	testValidateWithConfig(t)
	testValidateEmptyConfig(t)
}

func testValidateWithConfig(t *testing.T) {
	t.Run("validate kubernetes config", func(t *testing.T) {
		config := &KubernetesConfig{
			KubeConfigFile: "/path/to/kubeconfig",
			QPS:            100,
			Burst:          200,
		}

		errs := config.Validate()
		assert.Empty(t, errs)
	})
}

func testValidateEmptyConfig(t *testing.T) {
	t.Run("validate empty kubernetes config", func(t *testing.T) {
		config := &KubernetesConfig{}

		errs := config.Validate()
		assert.Empty(t, errs)
	})
}

func TestGetDefaultKubeConfigFile(t *testing.T) {
	testGetDefaultWithHomeDir(t)
	testGetDefaultWithUserCurrent(t)
	testGetDefaultNoHomeAvailable(t)
	testGetDefaultFileNotExists(t)
}

func testGetDefaultWithHomeDir(t *testing.T) {
	t.Run("get default kubeconfig file with home dir", func(t *testing.T) {
		setupHomeEnv(t, "/home/testuser")

		patches := gomonkey.NewPatches()
		defer patches.Reset()

		patches.ApplyFunc(homedir.HomeDir, func() string {
			return "/home/testuser"
		})

		patches.ApplyFunc(os.Stat, func(name string) (os.FileInfo, error) {
			if name == "/home/testuser/.kube/config" {
				return nil, nil
			}
			return nil, os.ErrNotExist
		})

		result := getDefaultKubeConfigFile()
		assert.Equal(t, "/home/testuser/.kube/config", result)
	})
}

func testGetDefaultWithUserCurrent(t *testing.T) {
	t.Run("get default kubeconfig file with user current", func(t *testing.T) {
		setupHomeEnv(t, "/home/testuser")

		patches := gomonkey.ApplyFunc(homedir.HomeDir, func() string {
			return ""
		})

		patches.ApplyFunc(user.Current, func() (*user.User, error) {
			return &user.User{HomeDir: "/home/testuser"}, nil
		})

		patches.ApplyFunc(os.Stat, func(name string) (os.FileInfo, error) {
			if name == "/home/testuser/.kube/config" {
				return nil, nil
			}
			return nil, os.ErrNotExist
		})

		defer patches.Reset()

		result := getDefaultKubeConfigFile()
		assert.Equal(t, "/home/testuser/.kube/config", result)
	})
}

func testGetDefaultNoHomeAvailable(t *testing.T) {
	t.Run("no home directory available", func(t *testing.T) {
		setupHomeEnv(t, "/home/testuser")

		patches := gomonkey.ApplyFunc(homedir.HomeDir, func() string {
			return ""
		})

		patches.ApplyFunc(user.Current, func() (*user.User, error) {
			return nil, errors.New("user error")
		})

		defer patches.Reset()

		result := getDefaultKubeConfigFile()
		assert.Empty(t, result)
	})
}

func testGetDefaultFileNotExists(t *testing.T) {
	t.Run("kubeconfig file does not exist", func(t *testing.T) {
		patches := gomonkey.ApplyFunc(homedir.HomeDir, func() string {
			return "/home/testuser"
		})

		patches.ApplyFunc(os.Stat, func(name string) (os.FileInfo, error) {
			return nil, os.ErrNotExist
		})

		defer patches.Reset()

		result := getDefaultKubeConfigFile()
		assert.Empty(t, result)
	})
}

func setupHomeEnv(t *testing.T, homePath string) {
	originalHome := os.Getenv("HOME")
	t.Setenv("HOME", homePath)

	t.Cleanup(func() {
		if originalHome != "" {
			err := os.Setenv("HOME", originalHome)
			if err != nil {
				return
			}
		}
	})
}
